package com.xyy.saas.payment.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.xyy.saas.payment.adapter.RouteManager;
import com.xyy.saas.payment.common.constants.ChannelConstants;
import com.xyy.saas.payment.cores.api.PaymentMerchantApi;
import com.xyy.saas.payment.cores.enums.AccountChannelEnum;
import com.xyy.saas.payment.cores.vo.QueryAccountVo;
import com.xyy.saas.payment.cores.vo.QueryFuminAccountVo;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.dao.model.PayAccount;
import com.xyy.saas.payment.dao.model.ThirdUserInfo;
import com.xyy.saas.payment.enums.BusinessType;
import com.xyy.saas.payment.exception.PaymentException;
import com.xyy.saas.payment.manage.cores.vo.ResultPageVo;
import com.xyy.saas.payment.pojo.bo.PlatformAccountBo;
import com.xyy.saas.payment.pojo.bo.QueryPlatformAccountViewBo;
import com.xyy.saas.payment.pojo.bo.UserBo;
import com.xyy.saas.payment.pojo.dto.QueryAccountDto;
import com.xyy.saas.payment.pojo.vo.DictEntity;
import com.xyy.saas.payment.pojo.vo.QueryPlatformAccountsVo;
import com.xyy.saas.payment.util.AmountCastUtil;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author wangtianqi
 * @date 2020/11/2 15:34
 */
@Service
@Slf4j
@DependsOn("apolloUtil")
public class PlatformAccountsManage implements InitializingBean {
    @Autowired
    private RouteManager routeManager;
    @Autowired
    private PayAccountService payAccountService;
    @Autowired
    private ThirdUserInfoService thirdUserInfoService;
    @Reference(version = "1.0.0")
    private PaymentMerchantApi paymentMerchantApi;

    private List<PlatformAccountBo> platformAccountBos = JSONUtils.parse2List(ApolloUtil.getProperty("platform_accounts"), PlatformAccountBo.class);

    public List<PlatformAccountBo> getPlatformAccount(){
        return Collections.unmodifiableList(platformAccountBos);
    }

    private QueryPlatformAccountViewBo convert2QueryPlatformAccountViewBo(PlatformAccountBo platformAccountBo) {
        QueryPlatformAccountViewBo bo = new QueryPlatformAccountViewBo();
        bo.setAccountId(platformAccountBo.getAccountId());
        bo.setAccountName(platformAccountBo.getAccountName());
        bo.setAccountType(platformAccountBo.getAccountType());
        bo.setBusinessType(BusinessType.valueOf(platformAccountBo.getBusinessType()).getDesc());
        bo.setResidual(refreshPlatFormData(platformAccountBo));
        bo.setSettleAccount(platformAccountBo.getSettleAccount());
        bo.setSettleName(platformAccountBo.getSettleName());
        return bo;
    }

    public ResultPageVo<List<QueryPlatformAccountViewBo>> getAccountsByCondition(QueryPlatformAccountsVo queryPlatformAccountsVo) {
        List<PlatformAccountBo> accountBos = new ArrayList<>();
        for(PlatformAccountBo platformAccountBo : platformAccountBos) {
            if(checkCondition(platformAccountBo, queryPlatformAccountsVo)) {
                accountBos.add(platformAccountBo);
            }
        }
        List<QueryPlatformAccountViewBo> queryPlatformAccountViewBos = new ArrayList<>();
        if(accountBos.size() > 0) {
            List<PlatformAccountBo> pageList = startPage(accountBos, queryPlatformAccountsVo.getPage(), queryPlatformAccountsVo.getPageSize());
            pageList.stream().forEach(e->queryPlatformAccountViewBos.add(convert2QueryPlatformAccountViewBo(e)));
        }
        return ResultPageVo.createSuccess(queryPlatformAccountsVo.getPage(), queryPlatformAccountsVo.getPageSize(), accountBos.size(), queryPlatformAccountViewBos);
    }

    private boolean checkCondition(PlatformAccountBo platformAccountBo ,QueryPlatformAccountsVo queryPlatformAccountsVo) {
        if(StringUtils.isNotEmpty(queryPlatformAccountsVo.getBusinessType()) && !queryPlatformAccountsVo.getBusinessType().equals(platformAccountBo.getBusinessType())) {
            return false;
        }
        if(StringUtils.isNotEmpty(queryPlatformAccountsVo.getAccountName()) && !queryPlatformAccountsVo.getAccountName().equals(platformAccountBo.getAccountName())) {
            return false;
        }
        if(StringUtils.isNotEmpty(queryPlatformAccountsVo.getSettleAccount()) && !queryPlatformAccountsVo.getSettleAccount().equals(platformAccountBo.getSettleAccount())) {
            return false;
        }
        if(StringUtils.isNotEmpty(queryPlatformAccountsVo.getAccountType()) && !queryPlatformAccountsVo.getAccountType().equals(platformAccountBo.getAccountType())) {
            return false;
        }
        return true;
    }

    private String refreshPlatFormData(PlatformAccountBo accountBo) {
        return String.valueOf(queryAccountBalance(accountBo.getAccountId()));
    }

    public PlatformAccountBo queryAccountByAccountId(String accountId) throws PaymentException {
        for(PlatformAccountBo bo : platformAccountBos) {
            if(bo.getAccountId().equals(accountId)) {
                bo.setResidual(refreshPlatFormData(bo));
                return bo;
            }
        }
        throw new PaymentException("账户户信息未找到");
    }

    /**
     * 查询指定账户的余额
     */
    public String queryAccountBalance(String userId) {
        return queryAccountBalance(userId, StringUtils.EMPTY);
    }

    /**
     * 查询指定账户的余额
     * @param accountNo           ：账号
     * @param balanceAccountType  : 类型
     * @return
     */
    public String queryAccountBalanceByNo(String accountNo, String balanceAccountType) {
        log.info("BalanceMonitorServiceIpml#queryAccountBalanceByNo query account request . accountNo:{} {} ", accountNo, balanceAccountType);
        try {
            ResultVO<com.xyy.saas.payment.cores.bo.UserBo> resultVO = paymentMerchantApi.queryAccountByAccountNo(accountNo, balanceAccountType);
            if (resultVO.isSuccess()) {
                return AmountCastUtil.castFen2Yuan(resultVO.getResult().getWithdrawableBalance());
            }
            return "0";
        } catch (Exception e) {
            log.error("BalanceMonitorServiceIpml#queryAccountBalanceByNo query account error . accountNo:{} {} ", accountNo, balanceAccountType);
            return "0";
        }
    }

    /**
     * 查询指定账户的余额
     */
    public String queryAccountBalance(String userId, String accountType) {
        QueryFuminAccountVo queryFuminAccountVo = new QueryFuminAccountVo();
        queryFuminAccountVo.setUserId(userId);
        PayAccount payAccount = payAccountService.getPayAccountByAccountId(queryFuminAccountVo.getUserId());
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(queryFuminAccountVo.getUserId());

        if(thirdUserInfo == null || thirdUserInfo.getThirdUserId() == null) {
            log.error("BalanceMonitorServiceIpml#queryAccountBalance query account is not exist. userId:{}", userId);
            return "0";
        }

        if(ChannelConstants.CHANNEL_YOP_BANK_NAME.equals(thirdUserInfo.getThirdType())) {
            QueryAccountVo queryAccountVo = new QueryAccountVo();
            queryAccountVo.setBusinessId(payAccount.getBusinessUserId());
            queryAccountVo.setBusinessIdType(payAccount.getBusinessIdType());
            queryAccountVo.setInvoker(payAccount.getBusinessIdType());
            queryAccountVo.setAccountChannelEnum(AccountChannelEnum.AGGREGATE);
            queryAccountVo.setBalanceAccountType(accountType);
            ResultVO<com.xyy.saas.payment.cores.bo.UserBo> resultVO = paymentMerchantApi.queryAccount(queryAccountVo, StringUtils.EMPTY);

            if(resultVO.isSuccess()) {
                return AmountCastUtil.castFen2Yuan(resultVO.getResult().getWithdrawableBalance());
            }
            else {
                return "0";
            }
        }

        if(ChannelConstants.CHANNEL_PINGAN_NAME.equals(thirdUserInfo.getThirdType())) {
            QueryAccountVo queryAccountVo = new QueryAccountVo();
            queryAccountVo.setBusinessId(payAccount.getBusinessUserId());
            queryAccountVo.setBusinessIdType(payAccount.getBusinessIdType());
            queryAccountVo.setInvoker(payAccount.getBusinessIdType());
            queryAccountVo.setAccountChannelEnum(AccountChannelEnum.AGGREGATE);
            queryAccountVo.setBalanceAccountType(accountType);
            ResultVO<com.xyy.saas.payment.cores.bo.UserBo> resultVO = paymentMerchantApi.queryAccount(queryAccountVo, StringUtils.EMPTY);
            log.info("######平安账户######，queryAccountVo={}，resultVO={}", JSONUtils.toJSON(queryAccountVo), JSONUtils.toJSON(resultVO));

            if(resultVO.isSuccess()) {
                return AmountCastUtil.castFen2Yuan(resultVO.getResult().getWithdrawableBalance());
            }
            else {
                return "0";
            }
        }

        QueryAccountDto queryAccountDto = new QueryAccountDto();
        queryAccountDto.setUserId(payAccount.getAccountId());
        queryAccountDto.setThirdUserId(thirdUserInfo.getThirdUserId());
        queryAccountDto.setBusinessIdType(payAccount.getBusinessIdType());
        UserBo userBo = null;

        try {
            userBo = routeManager.getAdapter(ChannelConstants.CHANNEL_FUMIN_BANK_NAME).queryAccount(queryAccountDto);
        }
        catch(PaymentException e) {
            log.error("BalanceMonitorServiceIpml#queryAccountBalance channel error. userId:{}", userId, e);
            return "0";
        }

        if(null == userBo) {
            log.error("BalanceMonitorServiceIpml#queryAccountBalance userBo is null. userId:{}", userId);
            return "0";
        }

        return AmountCastUtil.castFen2Yuan(userBo.getWithdrawableBalance());
    }

    private List<PlatformAccountBo> startPage(List<PlatformAccountBo> list, Integer pageNum,
                                 Integer pageSize) {
        if (list == null) {
            return null;
        }
        if (list.size() == 0) {
            return null;
        }
        // 记录总数
        Integer count = list.size();
        // 页数
        Integer pageCount = 0;
        if (count % pageSize == 0) {
            pageCount = count / pageSize;
        } else {
            pageCount = count / pageSize + 1;
        }
        // 开始索引
        int fromIndex = 0;
        // 结束索引
        int toIndex = 0;

        if (!pageNum.equals(pageCount)) {
            fromIndex = (pageNum - 1) * pageSize;
            toIndex = fromIndex + pageSize;
        } else {
            fromIndex = (pageNum - 1) * pageSize;
            toIndex = count;
        }

        List pageList = list.subList(fromIndex, toIndex);
        return pageList;
    }


    @Override
    public void afterPropertiesSet() {
        Set set = new HashSet();
        set.add("platform_accounts");
        //动态监听配置变化
        Config config = ConfigService.getAppConfig();
        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                List<PlatformAccountBo> tmpAccounts =  JSONUtils.parse2List(ApolloUtil.getProperty("platform_accounts"), PlatformAccountBo.class);
                if(tmpAccounts == null) {
                    log.error("PlatformAccountsManage#onChange change platformAccountBos  error");
                    return;
                }
                platformAccountBos = tmpAccounts;

                // 更新bean
                List<DictEntity> list = SpringUtils.getBean("fuminWithdrawBusinessTypeMap", List.class);
                if(!CollectionUtils.isEmpty(list)) {
                    // 清空
                    for (DictEntity dictEntity : list) {
                        if (!CollectionUtils.isEmpty(dictEntity.getChildrenList())) {
                            dictEntity.getChildrenList().clear();
                        }
                    }
                    for (PlatformAccountBo bo : platformAccountBos) {
                        for (DictEntity dictEntity : list) {
                            if (dictEntity.getValue().equals(bo.getBusinessType())) {
                                DictEntity dict = new DictEntity();
                                dict.setKey(bo.getAccountType());
                                dict.setLabel(bo.getAccountName());
                                dict.setValue(bo.getAccountType());
                                if (CollectionUtils.isEmpty(dictEntity.getChildrenList())) {
                                    List<DictEntity> tmp = new ArrayList<>();
                                    tmp.add(dict);
                                    dictEntity.setChildrenList(tmp);
                                } else {
                                    dictEntity.getChildrenList().add(dict);
                                }
                            }
                        }
                    }
                }
                log.info("PlatformAccountsManage#onChange change platformAccountBos  success platformAccountBos:{} " , JSON.toJSONString(platformAccountBos));
            }
        }, set);
    }
}
